/**
 * Copyright  2025, Hai Yue Xing He  ZHAO LIMIN
 *
 * @author        ZHAO LIMIN
 * @version       1.0.1
 * @since         2025-04
 *                数学工具类
 *
 * MersenneTwister.ts   是一种广泛使用的伪随机数生成算法，也被称为梅森旋转算法。
 * 构造函数：初始化 MersenneTwister 类，接受一个可选的种子参数 seed，如果未提供种子，则使用当前时间作为种子。
 *    init_genrand 方法：初始化随机数生成器的状态数组 mt。
 *    genrand_int32 方法：生成一个 32 位的随机整数。
 *    random 方法：生成一个介于 0（包含）和 1（不包含）之间的随机浮点数。
 */
export class MersenneTwister {
  private readonly N: number = 624
  private readonly M: number = 397
  private readonly MATRIX_A: number = 0x9908b0df
  private readonly UPPER_MASK: number = 0x80000000
  private readonly LOWER_MASK: number = 0x7fffffff
  private mt: number[] = new Array(this.N)
  private mti: number = this.N + 1

  constructor(seed: number = new Date().getTime()) {
    this.init_genrand(seed)
  }
  /**
   *
   * @param seed 设置新的Seek
   */
  public setSeed(seed: number): void {
    this.init_genrand(seed)
  }

  private init_genrand(s: number): void {
    this.mt[0] = s >>> 0
    for (this.mti = 1; this.mti < this.N; this.mti++) {
      const s = this.mt[this.mti - 1] ^ (this.mt[this.mti - 1] >>> 30)
      this.mt[this.mti] =
        ((((s & 0xffff0000) >>> 16) * 1812433253) << 16) + (s & 0x0000ffff) * 1812433253 + this.mti
      this.mt[this.mti] >>>= 0
    }
  }

  private genrand_int32(): number {
    let y: number
    const mag01: number[] = [0x0, this.MATRIX_A]
    if (this.mti >= this.N) {
      if (this.mti === this.N + 1) {
        this.init_genrand(5489)
      }
      for (let kk = 0; kk < this.N - this.M; kk++) {
        y = (this.mt[kk] & this.UPPER_MASK) | (this.mt[kk + 1] & this.LOWER_MASK)
        this.mt[kk] = this.mt[kk + this.M] ^ (y >>> 1) ^ mag01[y & 0x1]
      }
      for (let kk = this.N - this.M; kk < this.N - 1; kk++) {
        y = (this.mt[kk] & this.UPPER_MASK) | (this.mt[kk + 1] & this.LOWER_MASK)
        this.mt[kk] = this.mt[kk + (this.M - this.N)] ^ (y >>> 1) ^ mag01[y & 0x1]
      }
      y = (this.mt[this.N - 1] & this.UPPER_MASK) | (this.mt[0] & this.LOWER_MASK)
      this.mt[this.N - 1] = this.mt[this.M - 1] ^ (y >>> 1) ^ mag01[y & 0x1]
      this.mti = 0
    }
    y = this.mt[this.mti++]
    y ^= y >>> 11
    y ^= (y << 7) & 0x9d2c5680
    y ^= (y << 15) & 0xefc60000
    y ^= y >>> 18
    return y >>> 0
  }

  random(): number {
    return this.genrand_int32() * (1.0 / 4294967296.0)
  }
}
